define(['exports'], (function (exports) { 'use strict';

  class Constants {
  }
  Object.defineProperty(Constants, "Serial", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 0
  });
  Object.defineProperty(Constants, "Parallel", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 1
  });
  Object.defineProperty(Constants, "Node", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 2
  });
  Object.defineProperty(Constants, "GRAPH_DIRECTION_L2R", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 0
  });
  Object.defineProperty(Constants, "GRAPH_DIRECTION_T2B", {
      enumerable: true,
      configurable: true,
      writable: true,
      value: 1
  });

  /**
   * 计算图形
   * @param root 节点树根节点
   * @param config 配置
   * @returns
   */
  function toCalcGraphData(root, config = {}) {
      const opts = Object.assign({
          space: [70, 20], size: [100, 50], offset: [0, 0], arrow: 5,
          direction: Constants.GRAPH_DIRECTION_L2R, compact: false, debug: false,
          optimizeData: true
      }, config);
      const dnodes = [];
      // 简化空节点
      if (opts.optimizeData)
          toSimplifyNodes(root.children || [], opts.compact);
      const offset = [0, 0];
      offset[0] += opts.offset[0] + opts.space[0];
      offset[1] += opts.offset[1] + opts.space[1];
      // 计算坐标
      const rootNode = toCalcNodePosition.call(root, dnodes, offset, opts);
      const dsize = [0, 0];
      dsize[0] += rootNode.size[0] + offset[0] * 2;
      dsize[1] += rootNode.size[1] + offset[1] * 2;
      const dline = toCalcLine(rootNode, opts, dsize);
      const dlines = !opts.debug ? [dline] : dline.split('M').filter(d => d.trim()).map(d => `M${d}`);
      return { dnodes, dlines, dsize, root: rootNode };
  }
  /**
   * 计算节点坐标
   * @param this
   * @param offset 起始偏移量
   * @param opts 绘制对象
   * @returns
   */
  function toCalcNodePosition(dnodes, offset, opts) {
      this.position = [...offset];
      if (this.type === Constants.Node) {
          const [w, h] = opts.size;
          if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
              this.size = [w, h, w, 1, 1];
          }
          else {
              this.size = [w, h, h, 1, 1];
          }
          dnodes.push(this);
          return this;
      }
      this.size = [0, 0, 0, 0, 0];
      if (!this.children || this.children.length === 0)
          return this;
      let [x, y] = offset;
      // const size = [宽度,最高高度，第1层高度]
      if (this.type === Constants.Parallel) {
          let offset_space = 0;
          for (const child of this.children) {
              child.pname = this.name;
              toCalcNodePosition.call(child, dnodes, [x, y], opts);
              if (child.size[0] === 0)
                  continue;
              offset_space = opts.direction === Constants.GRAPH_DIRECTION_T2B
                  ? opts.space[0] : opts.space[1];
              // 盒子大小 宽度,最高高度，第1层高度
              if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
                  this.size[0] += child.size[0] + offset_space;
                  this.size[1] = Math.max(this.size[1], child.size[1]);
              }
              else {
                  this.size[0] = Math.max(this.size[0], child.size[0]);
                  this.size[1] += child.size[1] + offset_space;
              }
              this.size[2] += child.size[2] + offset_space;
              this.size[3] += child.size[3];
              this.size[4] += child.size[4];
              // y = Math.max(child.position[1] + offset_space_y, y);
              if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
                  if (child.position[0] + offset_space > x) {
                      this.position[0] = Math.max(offset[0], offset[0] + (child.position[0] - offset[0]) / 2);
                  }
                  x += child.size[2] + offset_space;
              }
              else {
                  if (child.position[1] + offset_space > y) {
                      this.position[1] = Math.max(offset[1], offset[1] + (child.position[1] - offset[1]) / 2);
                  }
                  y += child.size[2] + offset_space;
              }
              continue;
          }
          if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
              this.size[0] -= offset_space;
          }
          else {
              this.size[1] -= offset_space;
          }
          this.size[2] -= offset_space;
          return this;
      }
      if (this.type === Constants.Serial) {
          let max_pos = 0;
          let offset_space = 0;
          for (const child of this.children) {
              child.pname = this.name;
              toCalcNodePosition.call(child, dnodes, [x, y], opts);
              if (child.size[0] === 0)
                  continue;
              offset_space = opts.direction === Constants.GRAPH_DIRECTION_T2B
                  ? opts.space[1] : opts.space[0];
              // 盒子大小 宽度,最高高度，第1层高度
              if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
                  this.size[0] = Math.max(this.size[0], child.size[0]);
                  this.size[1] += child.size[1] + offset_space;
              }
              else {
                  this.size[0] += child.size[0] + offset_space;
                  this.size[1] = Math.max(this.size[1], child.size[1]);
              }
              this.size[2] = Math.max(this.size[2], child.size[2]);
              // 坐标
              if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
                  max_pos = Math.max(max_pos, child.position[0]);
                  y += child.size[1] + offset_space;
              }
              else {
                  x += child.size[0] + offset_space;
                  max_pos = Math.max(max_pos, child.position[1]);
              }
              if (this.size[3] === 0)
                  this.size[3] = child.size[3];
              this.size[4] = child.size[4];
              // y0 = Math.max(y0, child.position[1]);
              continue;
          }
          if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
              this.size[1] -= offset_space;
          }
          else {
              this.size[0] -= offset_space;
          }
          /** 修正坐标 */
          if (max_pos <= 0)
              return this;
          // 坐标是0:X, 1:Y
          const pos = opts.direction === Constants.GRAPH_DIRECTION_T2B ? 0 : 1;
          this.position[pos] = max_pos;
          for (const child of this.children) {
              const offset = max_pos - child.position[pos];
              let offset_x = opts.direction === Constants.GRAPH_DIRECTION_T2B ? offset : 0;
              let offset_y = opts.direction === Constants.GRAPH_DIRECTION_T2B ? 0 : offset;
              if (offset > 0)
                  toFixOffsetCalcNodePosition.call(child, offset_x, offset_y);
          }
          return this;
      }
      return this;
  }
  /**
   * 递归修正Y轴偏移量
   * @param this 节点
   * @param offset_x X轴偏移量
   * @param offset_y Y轴偏移量
   */
  function toFixOffsetCalcNodePosition(offset_x, offset_y) {
      this.position[0] += offset_x;
      this.position[1] += offset_y;
      for (const child of this.children) {
          toFixOffsetCalcNodePosition.call(child, offset_x, offset_y);
      }
  }
  /**
   * 计算节点线
   * @param this
   * @param opts
   * @param graphSize 图形大小
   * @returns
   */
  function toCalcLine(dnode, opts, graphSize) {
      let line = Constants.GRAPH_DIRECTION_T2B === opts.direction
          ? toCalcLineT2B.call(dnode, opts, graphSize)
          : toCalcLineL2R.call(dnode, opts, graphSize);
      line += toCalcLeanLine(dnode, opts);
      return line;
  }
  function toCalcLineL2R(opts, graphSize) {
      let line = '';
      // 画箭头
      if (this.type === Constants.Node && this.pname) {
          let [x, y] = this.position;
          // 起始点小于偏移开始节点, 无需画箭头
          if (x <= opts.offset[0] + opts.space[0])
              return line;
          const arrow = opts.arrow;
          if (arrow <= 0)
              return line;
          y += this.size[1] / 2;
          line += `M${x - arrow},${y - arrow} L${x - 1},${y} L${x - arrow},${y + arrow} `;
          return line;
      }
      if (!this.children || this.children.length === 0)
          return line;
      let childNext;
      let i = 0;
      for (const child of this.children) {
          // 空盒子
          if (child.size[0] === 0)
              continue;
          // 递归画子节点线
          line += toCalcLine(child, opts, graphSize);
          // 弟弟节点
          childNext = this.children[++i];
          // 普通节点不用画线
          if (this.type === Constants.Node)
              continue;
          // 父级盒子与子级盒子一样, 无需画该子级本身的线条
          if (this.size[0] === child.size[0] && this.size[1] === child.size[1])
              continue;
          // 并行情况
          if (this.type === Constants.Parallel) {
              // 画左边 -|
              const position = [...child.position];
              position[0] -= opts.space[0] / 2;
              position[1] += opts.size[1] / 2;
              let [x, y] = position;
              // 是否是多子节点
              // 是紧凑模型时或开始位置大于偏移位置
              if (opts.compact || x > opts.offset[0] + opts.space[0]) {
                  const move = [x + opts.space[0] / 2, y].join(',');
                  if (child.size[3] === 1) {
                      // 1.移动画线坐标
                      line += `M${move} `;
                      // 2.画横线
                      line += `L${position} `;
                  }
                  else {
                      line += `M${position} `;
                  }
                  // 3.画竖线
                  if (childNext && childNext.size[0] > 0) {
                      const position = [...childNext.position];
                      position[0] -= opts.space[0] / 2;
                      position[1] += opts.size[1] / 2;
                      line += `L${position} `;
                  }
              }
              // 画右边 -|
              x += opts.space[0] / 2;
              // 推算下个节点X坐标 = 本级节点X(包含自身宽度) + 间距 +下个盒子宽度 + 图偏移量;
              const x_next = x + this.size[0] + opts.space[0] + opts.offset[0];
              if (opts.compact || graphSize[0] > x_next) {
                  // 1.移动画线坐标
                  const move = [x + child.size[0], y];
                  if (child.size[4] !== 1)
                      move[0] += opts.space[0] / 2;
                  line += `M${move.join(',')} `;
                  // 2.画横线
                  line += `L${[x + this.size[0] + opts.space[0] / 2, y].join(',')} `;
                  // 3.画竖线
                  if (childNext) {
                      const position = [...childNext.position];
                      position[0] += this.size[0] + opts.space[0] / 2;
                      position[1] += opts.size[1] / 2;
                      line += `L${position} `;
                  }
              }
              continue;
          }
          if (this.type === Constants.Serial && childNext) {
              // 相邻节点为并行节点-不画串行先
              // if (child.type === childNext.type && child.type === Constants.Parallel) continue;
              // 起始坐标 >= 结束坐标 不用划线(无效- 不应该存在)
              // if (child.position[0] >= childNext.position[0]) continue;
              let [x, y] = child.position;
              y += opts.size[1] / 2;
              x += child.size[0];
              // 是否是多个子节点
              if (child.size[4] !== 1)
                  x += opts.space[0] / 2;
              const start = [x, y].join(',');
              x = childNext.position[0];
              // 是否是多个子节点
              if (childNext.size[3] !== 1)
                  x -= opts.space[0] / 2;
              const end = [x, y].join(',');
              // console.log(this.name, child.name, childNext.name, `M${start} L${end} `)
              line += `M${start} L${end} `;
              continue;
          }
      }
      return line;
  }
  function toCalcLineT2B(opts, graphSize) {
      let line = '';
      // 画箭头
      if (this.type === Constants.Node && this.pname) {
          let [x, y] = this.position;
          // 起始点小于偏移开始节点, 无需画箭头
          if (y <= opts.offset[1] + opts.space[1])
              return line;
          const arrow = opts.arrow;
          if (arrow <= 0)
              return line;
          x += this.size[0] / 2;
          line += `M${x - arrow},${y - arrow} L${x},${y - 1} L${x + arrow},${y - arrow} `;
          return line;
      }
      if (!this.children || this.children.length === 0)
          return line;
      let childNext;
      let i = 0;
      for (const child of this.children) {
          // 空盒子
          if (child.size[0] === 0)
              continue;
          // 递归画子节点线
          line += toCalcLine(child, opts, graphSize);
          // 弟弟节点
          childNext = this.children[++i];
          // 普通节点不用画线
          if (this.type === Constants.Node)
              continue;
          // 父级盒子与子级盒子一样, 无需画该子级本身的线条
          if (this.size[0] === child.size[0] && this.size[1] === child.size[1])
              continue;
          // 并行情况
          if (this.type === Constants.Parallel) {
              // 画左边 -|
              const position = [...child.position];
              position[0] += opts.size[0] / 2;
              position[1] -= opts.space[1] / 2;
              let [x, y] = position;
              // 是否是多子节点
              // 是紧凑模型时或开始位置大于偏移位置
              if (opts.compact || y > opts.offset[1] + opts.space[1]) {
                  const move = [x, y + opts.space[1] / 2].join(',');
                  if (child.size[3] === 1) {
                      // 1.移动画线坐标
                      line += `M${move} `;
                      // 2.画横线
                      line += `L${position} `;
                  }
                  else {
                      line += `M${position} `;
                  }
                  // 3.画竖线
                  if (childNext && childNext.size[0] > 0) {
                      const position = [...childNext.position];
                      position[0] += opts.size[0] / 2;
                      position[1] -= opts.space[1] / 2;
                      line += `L${position} `;
                  }
              }
              // 画右边 -|
              y += opts.space[1] / 2;
              // 推算下个节点X坐标 = 本级节点X(包含自身宽度) + 间距 +下个盒子宽度 + 图偏移量;
              const y_next = y + this.size[1] + opts.space[1] + opts.offset[1];
              if (opts.compact || graphSize[1] > y_next) {
                  // 1.移动画线坐标
                  const move = [x, y + child.size[1]];
                  if (child.size[4] !== 1)
                      move[1] += opts.space[1] / 2;
                  line += `M${move.join(',')} `;
                  // 2.画横线
                  line += `L${[x, y + this.size[1] + opts.space[1] / 2].join(',')} `;
                  // 3.画竖线
                  if (childNext) {
                      const position = [...childNext.position];
                      position[1] += this.size[1] + opts.space[1] / 2;
                      position[0] += opts.size[0] / 2;
                      line += `L${position} `;
                  }
              }
              continue;
          }
          if (this.type === Constants.Serial && childNext) {
              // 相邻节点为并行节点-不画串行先
              // if (child.type === childNext.type && child.type === Constants.Parallel) continue;
              // 起始坐标 >= 结束坐标 不用划线(无效- 不应该存在)
              // if (child.position[0] >= childNext.position[0]) continue;
              let [x, y] = child.position;
              x += opts.size[0] / 2;
              y += child.size[1];
              // 是否是多个子节点
              if (child.size[4] !== 1)
                  y += opts.space[1] / 2;
              const start = [x, y].join(',');
              y = childNext.position[1];
              // 是否是多个子节点
              if (childNext.size[3] !== 1)
                  y -= opts.space[1] / 2;
              const end = [x, y].join(',');
              // console.log(this.name, child.name, childNext.name, `M${start} L${end} `)
              line += `M${start} L${end} `;
              continue;
          }
      }
      return line;
  }
  /**
   * 添加依赖先
   * @param dnodes 节点
   * @param opts 配置
   * @returns 依赖线条
   */
  function toCalcLeanLine(node, opts) {
      const dnodes = toExtractNodes(node);
      const map = {};
      const leans = [];
      let leanline = '';
      for (const dnode of dnodes) {
          if (dnode.type !== Constants.Node)
              continue;
          map[dnode.name] = dnode;
          if (typeof dnode.lean !== 'string')
              continue;
          const lean = dnode.lean.replace(/\s/g, '');
          if (lean.length === 0)
              continue;
          const leannames = lean.split(',');
          for (const leanname of leannames) {
              leans.push([leanname, dnode.name]);
          }
      }
      if (leans.length === 0)
          return leanline;
      for (const lean of leans) {
          // 没有找到依赖的节点
          if (!map[lean[0]])
              continue;
          const n1 = map[lean[0]]; // 开始节点
          const n2 = map[lean[1]]; // 结束节点
          if (opts.direction === Constants.GRAPH_DIRECTION_T2B) {
              // 从上到下
              let [x, y] = n1.position;
              x += n1.size[0] / 2;
              y += n1.size[1];
              const start = [x, y].join(',');
              [x, y] = n2.position;
              x += n2.size[0] / 2;
              const end = [x, y].join(',');
              leanline += `M${start} L${end} `;
          }
          else {
              // 从左到右
              let [x, y] = n1.position;
              x += n1.size[0];
              y += n1.size[1] / 2;
              const start = [x, y].join(',');
              [x, y] = n2.position;
              y += n2.size[1] / 2;
              const end = [x, y].join(',');
              leanline += `M${start} L${end} `;
          }
      }
      return leanline;
  }
  /**
   * 简化节点
   * @param nodes 节点列表
   * @returns 节点列表
   */
  function toSimplifyNodes(nodes, compact = false) {
      if (nodes.length === 0)
          return nodes;
      const array = nodes.splice(0);
      let node;
      for (node of array) {
          node = toSimplifyNode.call(node, compact);
          if (node)
              nodes.push(node);
      }
      return nodes;
  }
  function toSimplifyNode(compact = false) {
      if (this.type === Constants.Node)
          return this;
      if (!this.children || this.children.length === 0)
          return undefined;
      if (this.children.length === 1)
          return toSimplifyNode.call(this.children[0]);
      for (let i = 0; i < this.children.length; i++) {
          let child = this.children[i];
          if (child.type === Constants.Node)
              continue;
          const rchild = toSimplifyNode.call(child);
          if (rchild !== child || this.type === child.type) {
              if (!child.children || child.children.length === 0) {
                  this.children.splice(i, 1);
                  i--;
                  continue;
              }
              this.children.splice(i, 1, ...child.children);
              i--;
              continue;
          }
      }
      return this;
  }
  function toExtractNodes(dnode, dnodes = []) {
      if (dnode.type === Constants.Node) {
          dnodes.push(dnode);
          return dnodes;
      }
      for (const child of dnode.children) {
          toExtractNodes(child, dnodes);
      }
      return dnodes;
  }

  /**
   * 模拟节点数组
   * @param max 最大模拟节点数
   * @param compact 是否紧凑节点
   * @returns 节点集合
   */
  function mockNodes(max = 20, weight = 0) {
      var _a;
      let index = 0;
      let count = 0;
      const nodes = [];
      function mockNode() {
          let type = (index === 0 ? Constants.Serial : Math.floor(Math.random() * (3 + weight)));
          if (type >= 2)
              type = 2;
          const name = ['S', 'P', 'N'][type] + index++;
          const node = new MockXNode(type, name);
          nodes.push(node);
          if (type === Constants.Node) {
              count++;
              return node;
          }
          const len = Math.floor(Math.random() * 7) + 3;
          for (let i = 0; i < len; i++) {
              if (count >= max)
                  break;
              node.children.push(mockNode());
          }
          return node;
      }
      mockNode();
      while (max > count) {
          (_a = nodes[0].children) === null || _a === void 0 ? void 0 : _a.push(mockNode());
      }
      return nodes;
  }
  /** 模拟基础数据节点 */
  class MockXNode {
      constructor(type, name) {
          Object.defineProperty(this, "type", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "name", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: void 0
          });
          Object.defineProperty(this, "children", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: []
          });
          // 计算出来的值
          Object.defineProperty(this, "size", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: [0, 0, 0, 0, 0]
          });
          Object.defineProperty(this, "position", {
              enumerable: true,
              configurable: true,
              writable: true,
              value: [0, 0]
          });
          this.type = type;
          this.name = name;
      }
  }

  exports.Constants = Constants;
  exports.MockXNode = MockXNode;
  exports.mockNodes = mockNodes;
  exports.toCalcGraphData = toCalcGraphData;
  exports.toCalcLeanLine = toCalcLeanLine;
  exports.toCalcLine = toCalcLine;
  exports.toSimplifyNodes = toSimplifyNodes;

  Object.defineProperty(exports, '__esModule', { value: true });

}));
